package ai.reseaux;

import org.encog.ml.data.MLData;
import org.encog.ml.data.MLDataPair;
import org.encog.ml.data.MLDataSet;
import org.encog.ml.train.MLTrain;
import org.encog.neural.networks.BasicNetwork;
import org.encog.neural.networks.training.propagation.back.Backpropagation;

public abstract class ReseauAbstract {
	
	protected BasicNetwork network;
	
	/**
	 * Apprendre au reseau des exemple
	 * @param learningSet un MLDataSet contenant les exemples d'apprentissage
	 * @param le coeficient d'aprentissage (alpha dans le cours)
	 * @return l'erreur obtenu après apprentissage
	 */
	public double learn(MLDataSet learningSet, double learningRate, int iterations) {
		final MLTrain train = new Backpropagation(network, learningSet, learningRate, 0.0);
		for (int i =0; i < iterations ; i++) {
			train.iteration();
		}
		train.finishTraining();
		learningSet.close();
		return train.getError();
	}
	
	/** Un helper qui retourne la label prédit par le reseau */
	private int getComputeLabel(MLData output) {
		
		 /* on prend l'idex du maximum du tableau output
		 (ce que le reseau considère comme le plus probalble)*/
		double tempMax = 0.0;
		int computeLabel = 0;
		double[] rawOutput = output.getData();
		for (int i=0; i< rawOutput.length ; i++) {
			if (rawOutput[i] >= tempMax) {
				tempMax = rawOutput[i];
				computeLabel = i;
			}
		}
		return computeLabel;
	}
	
	/** Un helper qui retourne le label **/
	private int getLabel(MLData ideal) {
		
		//l'index de l'idéal pour lequel la valeur est 1.0
		double[] rawIdeal = ideal.getData();
		int label = 0;
		for (int i=0; i < rawIdeal.length; i++) {
			if (rawIdeal[i] == 1.0) {
				label = i;
			}
		}
		return label;
	}
	
	/**
	 * Test le reseau sur un ensemble d'exemple
	 * @param testSet un MLDataSet contenant les exemples de test
	 * @return l'erreur obtenu sur l'ensemble de test
	 */
	public double test(MLDataSet testSet) {
		int errorCount = 0;
		int imageCont = 1;
		for(MLDataPair pair: testSet ) {
			
			/* Calculer les résultats */
			final MLData output = network.compute(pair.getInput());
			int computeLabel = getComputeLabel(output); 
			int label = getLabel(pair.getIdeal());
			
			//Mettre à jour l'erreur
			if (computeLabel != label) {
				errorCount++;
			}
			
			imageCont++;
		}
		testSet.close();
		return ((double)errorCount / (double) imageCont);
	}

}
